using System;
using System.Collections;
using System.Configuration;
using System.Globalization;
using System.Web;
using AspNetCaching = System.Web.Caching;
using NWrapper.Attributes;
using NWrapper.Config;

namespace NWrapper.Cache
{
	/// <summary>
	/// Singleton implementation of a cache that uses the <see cref="System.Web.Caching.Cache"/>.
	/// </summary>
	/// <remarks>
	/// Objects stored in the Asp.Net cache are not serialized, so a retrieved object will be the
	/// same object reference as the stored object.
	/// </remarks>
	[Singleton]
	public class AspNetCache : ICache
	{
		private static readonly AspNetCache _instance = new AspNetCache();

		/// <summary>
		/// Static constructor to enforce singleton.
		/// </summary>
		static AspNetCache()
		{
		}

		/// <summary>
		/// Gets the singleton instance for the cache.
		/// </summary>
		public static AspNetCache Instance
		{
			get { return _instance; }
		}

		#region ICache Members
		/// <summary>
		/// Initializes the underlying cache.
		/// </summary>
		/// <param name="settings">The cache settings.</param>
		public void Initialize(CacheSettings settings)
		{
			//nothing to do
		}

		/// <summary>
		/// Gets or sets the cache item with the specified key.
		/// </summary>
		/// <param name="key">The key of the cache item.</param>
		/// <returns>The cache item's value.</returns>
        /// <remarks>Indexer forwards all requests to the <see cref="Get"/> or <see cref="Set(object, object)"/> method.</remarks>
		public object this[object key]
		{
			get { return this.Get(key); }
			set { this.Set(key, value); }
		}

		/// <summary>
		/// Retrieves an object from the cache. If the ASP.Net cache is unavailable, this
		/// will always return null.
		/// </summary>
		/// <param name="key">The key of the object.</param>
		/// <returns>The cached object.</returns>
		public object Get(object key)
		{
			if (key == null)
				return null;

			return HttpRuntime.Cache[CacheHelper.GetCacheKey(key)];
		}

		/// <summary>
		/// Places an item in the cache. If the ASP.Net cache is unavailable, this
		/// will do nothing.
		/// </summary>
		/// <param name="key">The key of the object.</param>
		/// <param name="value">The cached object.</param>
		public void Set(object key, object value)
		{
			ExceptionHelper.AssertIfNull(key);

			HttpRuntime.Cache[CacheHelper.GetCacheKey(key)] = value;
		}

		/// <summary>
		/// Place an item in the cache that will expire after the given time span.
		/// If the ASP.Net cache is unavailable, this will do nothing.
		/// </summary>
		/// <param name="key">The key of the object.</param>
		/// <param name="value">The cached object.</param>
		/// <param name="timeToExpire">The <see cref="TimeSpan"/> to use for
		/// item expiration.</param>
		public void Set(object key, object value, TimeSpan timeToExpire)
		{
			ExceptionHelper.AssertIfNull(key, timeToExpire);

			HttpRuntime.Cache.Insert(CacheHelper.GetCacheKey(key), value, null, AspNetCaching.Cache.NoAbsoluteExpiration, timeToExpire);
		}

		/// <summary>
		/// Place an item in the cache with the specified cache expiration.
		/// If the ASP.Net cache is unavailable, this will do nothing.
		/// </summary>
		/// <param name="key">The key of the object.</param>
		/// <param name="value">The cached object.</param>
		/// <param name="expiration">The <see cref="DateTime"/> to use for
		/// item expiration.</param>
		public void Set(object key, object value, DateTime expiration)
		{
			ExceptionHelper.AssertIfNull(key, expiration);

			HttpRuntime.Cache.Insert(CacheHelper.GetCacheKey(key), value, null, expiration, AspNetCaching.Cache.NoSlidingExpiration);
		}

		/// <summary>
		/// Determines whether an object with the given key exists in the cache.
		/// If the ASP.Net cache is unavailable, this will always return false.
		/// </summary>
		/// <param name="key">The key of the object.</param>
		/// <returns>True if the key exists in the cache, false otherwise.</returns>
		public bool Contains(object key)
		{
			if (key == null)
				return false;

			return (this.Get(key) != null);
		}

		/// <summary>
		/// Removes an object from the cache. If the ASP.Net cache is unavailable, this
		/// will do nothing.
		/// </summary>
		/// <param name="key">The key of the object.</param>
		public void Remove(object key)
		{
			if (key != null)
			{
				HttpRuntime.Cache.Remove(CacheHelper.GetCacheKey(key));
			}
		}

		/// <summary>
		/// Removes all objects from the cache. If the ASP.Net cache is unavailable, this
		/// will do nothing.
		/// </summary>
		public void Clear()
		{
			foreach (DictionaryEntry item in HttpRuntime.Cache)
			{
				HttpRuntime.Cache.Remove(CacheHelper.GetCacheKey(item.Key));
			}
		}
		#endregion
	}
}
